package org.xp.judgeplatform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.xp.judgeplatform.exception.BusinessException;
import org.xp.judgeplatform.mapper.SubmissionMapper;
import org.xp.judgeplatform.mapper.TestCaseMapper;
import org.xp.judgeplatform.pojo.dto.JudgeDTO.JudgeRequestDTO;
import org.xp.judgeplatform.pojo.entity.Submission;
import org.xp.judgeplatform.pojo.entity.TestCase;
import org.xp.judgeplatform.pojo.enums.JudgeStatus;
import org.xp.judgeplatform.pojo.vo.JudgeVO.JudgeResultVO;
import org.xp.judgeplatform.service.JudgeService;
import org.xp.judgeplatform.service.LanguageExecutor;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@AllArgsConstructor
public class JudgeServiceImpl implements JudgeService {

    private final TestCaseMapper testCaseMapper;
    private final SubmissionMapper submissionMapper;
    private final ObjectMapper objectMapper;
    private final Map<String, LanguageExecutor> languageExecutors;

    @Override
    public JudgeResultVO judgeCode(JudgeRequestDTO judgeRequest) {
        Long submissionId = null;
        try {
            // 1. 创建提交记录
            submissionId = createSubmission(judgeRequest);
            
            // 2. 获取测试用例
            List<TestCase> testCases = getTestCases(judgeRequest.getProblemId());
            if (testCases == null || testCases.isEmpty()) {
                return updateSubmissionAndReturn(submissionId, createErrorResult("题目没有测试用例"));
            }

            // 3. 构建测试用例JSON
            String testCasesJson = buildTestCasesJson(testCases);

            // 4. 获取对应语言的执行器
            LanguageExecutor executor = getLanguageExecutor(judgeRequest.getLanguage());

            // 5. 执行判题
            String judgeResultJson = executor.execute(
                judgeRequest.getCode(),
                testCasesJson,
                judgeRequest.getFunctionName()
            );

            // 6. 解析判题结果
            JudgeResultVO result = parseJudgeResult(judgeResultJson);
            
            // 7. 更新提交记录
            return updateSubmissionAndReturn(submissionId, result);

        } catch (SecurityException e) {
            log.warn("代码安全检查失败: {}", e.getMessage());
            return updateSubmissionAndReturn(submissionId, createErrorResult("代码包含不安全操作: " + e.getMessage()));
        } catch (Exception e) {
            log.error("判题过程中发生异常", e);
            return updateSubmissionAndReturn(submissionId, createErrorResult("系统错误: " + e.getMessage()));
        }
    }

    /**
     * 创建提交记录
     */
    private Long createSubmission(JudgeRequestDTO request) {
        Submission submission = new Submission();
        submission.setProblemId(request.getProblemId());
        submission.setUserId(request.getUserId());
        submission.setCode(request.getCode());
        submission.setLanguage(request.getLanguage());
        submission.setStatus(JudgeStatus.JUDGING.getCode());
        submission.setScore(0);
        submission.setTotalScore(100);
        submission.setPassedCases(0);
        submission.setTotalCases(0);
        submission.setExecutionTime(BigDecimal.ZERO);
        submission.setMemoryUsage(BigDecimal.ZERO);
        // created_at 字段由 MyBatis-Plus 自动填充机制处理
        
        submissionMapper.insert(submission);
        return submission.getId();
    }

    /**
     * 更新提交记录并返回结果
     */
    private JudgeResultVO updateSubmissionAndReturn(Long submissionId, JudgeResultVO result) {
        if (submissionId != null) {
            try {
                Submission submission = new Submission();
                submission.setId(submissionId);
                submission.setStatus(result.getStatus().getCode());
                submission.setScore(result.getScore());
                submission.setTotalScore(result.getTotalScore());
                submission.setPassedCases(result.getPassedCases());
                submission.setTotalCases(result.getTotalCases());
                submission.setExecutionTime(result.getExecutionTime());
                submission.setMemoryUsage(result.getMemoryUsage());
                submission.setErrorMessage(result.getErrorMessage());
                submission.setJudgeResult(objectMapper.writeValueAsString(result.getTestResults()));
                submission.setJudgedAt(LocalDateTime.now());
                
                submissionMapper.updateById(submission);
            } catch (Exception e) {
                log.error("更新提交记录失败", e);
            }
        }
        return result;
    }

    /**
     * 根据语言获取对应的执行器
     */
    private LanguageExecutor getLanguageExecutor(String language) {
        LanguageExecutor executor = languageExecutors.get(language.toLowerCase());
        if (executor == null) {
            throw new BusinessException(400, "不支持的编程语言: " + language);
        }
        return executor;
    }

    /**
     * 获取指定问题的测试用例
     */
    private List<TestCase> getTestCases(Long problemId) {
        QueryWrapper<TestCase> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("problem_id", problemId)
                    .orderByDesc("is_sample")
                    .orderByAsc("id");
        return testCaseMapper.selectList(queryWrapper);
    }

    /**
     * 构建测试用例的JSON字符串
     */
    private String buildTestCasesJson(List<TestCase> testCases) throws JsonProcessingException {
        List<TestCaseJson> testCaseList = new ArrayList<>();
        for (TestCase tc : testCases) {
            TestCaseJson tcJson = new TestCaseJson();
            tcJson.input = tc.getInputData() != null ? tc.getInputData() : "";
            tcJson.expected = tc.getExpectedOutput() != null ? tc.getExpectedOutput() : "";
            tcJson.description = tc.getDescription() != null ? tc.getDescription() : "";
            testCaseList.add(tcJson);
        }
        return objectMapper.writeValueAsString(testCaseList);
    }

    /**
     * 解析判题系统的响应
     */
    private JudgeResultVO parseJudgeResult(String judgeResultJson) throws Exception {
        try {
            JsonNode jsonNode = objectMapper.readTree(judgeResultJson);
            
            JudgeResultVO result = new JudgeResultVO();
            
            // 解析基本信息
            String statusCode = jsonNode.path("status").asText("SE");
            result.setStatus(JudgeStatus.fromCode(statusCode));
            result.setScore(jsonNode.path("score").asInt(0));
            result.setTotalScore(jsonNode.path("total_score").asInt(100));
            result.setPassedCases(jsonNode.path("passed_cases").asInt(0));
            result.setTotalCases(jsonNode.path("total_cases").asInt(0));
            result.setExecutionTime(BigDecimal.valueOf(jsonNode.path("execution_time").asDouble(0.0)));
            result.setMemoryUsage(BigDecimal.valueOf(jsonNode.path("memory_usage").asDouble(0.0)));
            result.setErrorMessage(jsonNode.path("error_message").asText(""));
            
            // 解析测试用例结果
            List<JudgeResultVO.TestCaseResultVO> testResults = new ArrayList<>();
            JsonNode testResultsNode = jsonNode.path("test_results");
            if (testResultsNode.isArray()) {
                for (JsonNode testResult : testResultsNode) {
                    JudgeResultVO.TestCaseResultVO tcResult = new JudgeResultVO.TestCaseResultVO();
                    tcResult.setCaseId(testResult.path("case_id").asInt());
                    tcResult.setInput(testResult.path("input").asText(""));
                    tcResult.setExpected(testResult.path("expected").asText(""));
                    tcResult.setActual(testResult.path("actual").asText(""));
                    tcResult.setStatus(JudgeStatus.fromCode(testResult.path("status").asText("SE")));
                    tcResult.setTime(BigDecimal.valueOf(testResult.path("time").asDouble(0.0)));
                    tcResult.setMemory(BigDecimal.valueOf(testResult.path("memory").asDouble(0.0)));
                    tcResult.setError(testResult.path("error").asText(""));
                    testResults.add(tcResult);
                }
            }
            result.setTestResults(testResults);
            
            return result;
        } catch (Exception e) {
            log.error("解析判题结果失败: {}", judgeResultJson, e);
            throw new Exception("解析判题结果失败: " + e.getMessage());
        }
    }

    /**
     * 创建错误结果
     */
    private JudgeResultVO createErrorResult(String errorMessage) {
        JudgeResultVO result = new JudgeResultVO();
        result.setStatus(JudgeStatus.SYSTEM_ERROR);
        result.setScore(0);
        result.setTotalScore(100);
        result.setPassedCases(0);
        result.setTotalCases(0);
        result.setExecutionTime(BigDecimal.ZERO);
        result.setMemoryUsage(BigDecimal.ZERO);
        result.setErrorMessage(errorMessage);
        result.setTestResults(new ArrayList<>());
        return result;
    }

    /**
     * 测试用例JSON结构
     */
    private static class TestCaseJson {
        public String input;
        public String expected;
        public String description;
    }
}
